﻿#include "CustomChart.h"


CustomChart::CustomChart(){
    _infoObject = new CustomChartCurveInfoObject;
    gQmlEngine->setObjectOwnership(_infoObject, QQmlApplicationEngine::CppOwnership);
}

CustomChart::~CustomChart(){
    if(_infoObject)     { delete _infoObject;  _infoObject = nullptr; }
}


CustomChartCurveInfoObject* CustomChart::getCurveInfo(){


    QTime timer;
    timer.start();

    _infoObject->_chartMinX = _minX;
    _infoObject->_chartMaxX = _maxX;
    _infoObject->_chartMinY = _minY;
    _infoObject->_chartMaxY = _maxY;

    _infoObject->clearAll();

    foreach(stCurve curve, _curveList){

        // 归一化后的曲线点
        _infoObject->_normPointList.push_back(QVector<double>());
        foreach(QPointF point, curve.normPointList){
            _infoObject->_normPointList.back().push_back(point.x());
            _infoObject->_normPointList.back().push_back(point.y());
        }
        // 贝塞尔曲线点
        _infoObject->_bezierPointList.push_back(QVector<double>());
        foreach(QPointF point, curve.bezierPointList){
            _infoObject->_bezierPointList.back().push_back(point.x());
            _infoObject->_bezierPointList.back().push_back(point.y());
        }
        _infoObject->_lineWidth.push_back(curve.lineWidth);
        _infoObject->_curveType.push_back((int)curve.curveType);
        _infoObject->_color.push_back(curve.color);
        _infoObject->_scatterType.push_back((int)curve.scatterType);
    }

    _infoObject->_tickValueX = _tickValueX;
    _infoObject->_tickValueY = _tickValueY;
    _infoObject->_tickPercentX = _tickPercentX;
    _infoObject->_tickPercentY = _tickPercentY;


//    qDebug() << "CPP-GenerateVariantMap" << QString::number(timer.elapsed()) + "ms";
    return _infoObject;
}

CustomChartCurveInfoObject* CustomChart::getCurveInfo_fullImage(){


    _infoObject->_chartMinX = _fullMinX;
    _infoObject->_chartMaxX = _fullMaxX;
    _infoObject->_chartMinY = _fullMinY;
    _infoObject->_chartMaxY = _fullMaxY;

    _infoObject->clearAll();

    foreach(stCurve curve, _curveList){

        // 归一化后的曲线点
        _infoObject->_normPointList.push_back(QVector<double>());
        foreach(QPointF point, curve.normPointList_full){
            _infoObject->_normPointList.back().push_back(point.x());
            _infoObject->_normPointList.back().push_back(point.y());
        }
        // 贝塞尔曲线点
        _infoObject->_bezierPointList.push_back(QVector<double>());
        foreach(QPointF point, curve.bezierPointList_full){
            _infoObject->_bezierPointList.back().push_back(point.x());
            _infoObject->_bezierPointList.back().push_back(point.y());
        }
        _infoObject->_lineWidth.push_back(curve.lineWidth);
        _infoObject->_curveType.push_back((int)curve.curveType);
        _infoObject->_color.push_back(curve.color);
        _infoObject->_scatterType.push_back((int)curve.scatterType);
    }

    _infoObject->_tickValueX   = _fullTickValueX;
    _infoObject->_tickValueY   = _fullTickValueY;
    _infoObject->_tickPercentX = _fullTickPercentX;
    _infoObject->_tickPercentY = _fullTickPercentY;

    return _infoObject;
}

void CustomChart::clear(){
    _curveList.clear();
}

void CustomChart::refresh(){
    calculate();
    emit sigRefresh();
}

void CustomChart::initShowRange(){

    _showRangeX1 = 0;
    _showRangeX2 = 1;
    _showRangeY1 = 0;
    _showRangeY2 = 1;
    emit sigResetRange();
}

void CustomChart::appendCurve(QString name, QVector<QPointF> pointList, QColor color, int lineWidth, enCurveType type, enScatterType scType){
    stCurve curve;
    curve.pointList = pointList;
    curve.color = color;
    curve.curveType = type;
    curve.lineWidth = lineWidth;
    curve.scatterType = scType;

    curve.maxX = _defaultMaxX;
    curve.maxY = _defaultMaxY;
    curve.minX = _defaultMinX;
    curve.minY = _defaultMinY;
    foreach(QPointF point, pointList){
        curve.maxX = std::max(curve.maxX, point.x());
        curve.maxY = std::max(curve.maxY, point.y());
        curve.minX = std::min(curve.minX, point.x());
        curve.minY = std::min(curve.minY, point.y());
    }
    _curveList[name] = curve;
}

void CustomChart::printCurveInfo(){
    QString str = "CURVE_LIST: { ";
    foreach(QString name, _curveList.keys()){
        str.append(name + " ");
    }
    str.append("}");
    qDebug() << str;
}

void CustomChart::calculate(){

    QTime timer;
    timer.start();

    calRange();
    calNorm();
    calBezier();
    calMesh();

//    qDebug() << "CPP-CalculateTime:" << QString::number(timer.elapsed()) + "ms";

}

void CustomChart::calRange(){
    _fullMaxX = _defaultMaxX;
    _fullMaxY = _defaultMaxY;
    _fullMinX = _defaultMinX;
    _fullMinY = _defaultMinY;
    foreach(stCurve curve, _curveList){
        _fullMaxX = std::max(_fullMaxX, curve.maxX);
        _fullMinX = std::min(_fullMinX, curve.minX);
        _fullMaxY = std::max(_fullMaxY, curve.maxY);
        _fullMinY = std::min(_fullMinY, curve.minY);
    }

    _fullMaxY = calCeilRange(_fullMaxY);

    if(_isFixedMaxX)    { _fullMaxX = _fixedMaxX; }
    if(_isFixedMinX)    { _fullMinX = _fixedMinX; }
    if(_isFixedMaxY)    { _fullMaxY = _fixedMaxY; }
    if(_isFixedMinY)    { _fullMinY = _fixedMinY; }


    _minX = (_fullMaxX-_fullMinX) * _showRangeX1 + _fullMinX;
    _maxX = (_fullMaxX-_fullMinX) * _showRangeX2 + _fullMinX;
    _minY = (_fullMaxY-_fullMinY) * _showRangeY1 + _fullMinY;
    _maxY = (_fullMaxY-_fullMinY) * _showRangeY2 + _fullMinY;

}

void CustomChart::calNorm(){
    for(auto iter = _curveList.begin(); iter != _curveList.end(); iter ++){
        stCurve &curve = iter.value();
        curve.normPointList.clear();
        curve.normPointList_full.clear();
        for(int i = 0; i < curve.pointList.size(); i ++){

            QPointF& point = curve.pointList[i];

            // 如果当前点、上一个点、下一个点都不在_minX和maxX之间，则不传入
            if(i >= 1 && i < curve.pointList.size()-1){

            }

            curve.normPointList.push_back(QPointF((point.x()-_minX)/(_maxX-_minX),
                                                  (point.y()-_minY)/(_maxY-_minY)));
            curve.normPointList_full.push_back(QPointF((point.x()-_fullMinX)/(_fullMaxX-_fullMinX),
                                                  (point.y()-_fullMinY)/(_fullMaxY-_fullMinY)));
        }
    }
}

void CustomChart::calBezier(){
    QPointF ps, pe;          // 临时变量
    double dx, dy, blen;     // 临时变量
    double bezierSpline = 0.3;  // 参数0~1，贝塞尔曲线弯曲程度
    for(auto iter = _curveList.begin(); iter != _curveList.end(); iter ++){
        stCurve &curve = iter.value();
        curve.bezierPointList.clear();
        curve.bezierPointList_full.clear();

        // 放缩后的曲线 ------------------------------->
        if(curve.normPointList.size() <= 1){
            continue;       // 曲线长度小于等于1时无贝塞尔曲线
        }
        for(int i = 0; i < curve.normPointList.size() - 1; i ++){
            if(i == 0){
                curve.bezierPointList.push_back(curve.normPointList[0]);
                continue;
            }
            // 两个点之间的斜率
            ps = curve.normPointList[i-1];  pe = curve.normPointList[i+1];
            dx = pe.x() - ps.x();           dy = pe.y() - ps.y();
            blen = std::sqrt(dy*dy+dx*dx);
            dx = dx * bezierSpline;
            dy = dy * bezierSpline;
            curve.bezierPointList.push_back(QPointF(curve.normPointList[i].x()-dx*0.5,
                                                    curve.normPointList[i].y()-dy*0.5));
            curve.bezierPointList.push_back(QPointF(curve.normPointList[i].x()+dx*0.5,
                                                    curve.normPointList[i].y()+dy*0.5));
        }
        curve.bezierPointList.push_back(curve.normPointList.back());
        // 计算结束 ---------------------------------------->

        // 没放缩的曲线 ------------------------------------->
        if(curve.normPointList_full.size() <= 1){
            continue;       // 曲线长度小于等于1时无贝塞尔曲线
        }
        for(int i = 0; i < curve.normPointList_full.size() - 1; i ++){
            if(i == 0){
                curve.bezierPointList_full.push_back(curve.normPointList_full[0]);
                continue;
            }
            // 两个点之间的斜率
            ps = curve.normPointList_full[i-1];  pe = curve.normPointList_full[i+1];
            dx = pe.x() - ps.x();           dy = pe.y() - ps.y();
            blen = std::sqrt(dy*dy+dx*dx);
            dx = dx * bezierSpline;
            dy = dy * bezierSpline;
            curve.bezierPointList_full.push_back(QPointF(curve.normPointList_full[i].x()-dx*0.5,
                                                    curve.normPointList_full[i].y()-dy*0.5));
            curve.bezierPointList_full.push_back(QPointF(curve.normPointList_full[i].x()+dx*0.5,
                                                    curve.normPointList_full[i].y()+dy*0.5));
        }
        curve.bezierPointList_full.push_back(curve.normPointList_full.back());
        // 计算结束 ----------------------------------------->
    }
}

double CustomChart::calCeilRange(double maxVal){

    double ynum = 0, temp = maxVal;
    while(temp/10 > 10){
        ynum ++;
        temp = temp / 10;
    }   // ynum: maxVal是几位数
    double ybase = std::pow(10, ynum);        // 调节0控制保留几位取整
    maxVal = std::ceil(maxVal / ybase) * ybase;
    return maxVal;

}

void CustomChart::clearFixedRange(){
    _isFixedMaxX = false;
    _isFixedMaxY = false;
    _isFixedMinX = false;
    _isFixedMinY = false;
}

void CustomChart::setFixedMaxX(double value){
    _isFixedMaxX = true;
    _fixedMaxX = value;
}
void CustomChart::setFixedMinX(double value){
    _isFixedMinX = true;
    _fixedMinX = value;
}
void CustomChart::setFixedMaxY(double value){
    _isFixedMaxY = true;
    _fixedMaxY = value;
}
void CustomChart::setFixedMinY(double value){
    _isFixedMinY = true;
    _fixedMinY = value;
}
void CustomChart::setShowRange(double x1, double x2, double y1, double y2){
    _showRangeX1 = x1;
    _showRangeX2 = x2;
    _showRangeY1 = y1;
    _showRangeY2 = y2;
}
void CustomChart::setShowRangeX(double x1, double x2){
    _showRangeX1 = x1;
    _showRangeX2 = x2;
}
void CustomChart::setShowRangeY(double y1, double y2){
    _showRangeY1 = y1;
    _showRangeY2 = y2;
}
QVector<double> CustomChart::getShowRange(){
    return QVector<double>({_showRangeX1, _showRangeX2, _showRangeY1, _showRangeY2});
}


QPointF CustomChart::findPointInScope_byScalePosition(double dx, double dy, double dRadius){

    // 将dx、dy、radius映射到真实范围
    double px = dx * (_maxX - _minX) + _minX;
    double py = dy * (_maxY - _minY) + _minY;
    double rx = dRadius * (_maxX - _minX);
    double ry = dRadius * (_maxY - _minY);

    QPointF point_origin(dx, dy);

    QPointF point_res(-1, -1);
    double  minDistance = 10000000000;

    // 遍历所有的点
    foreach(stCurve curve, _curveList){
        foreach(QPointF point, curve.normPointList){
            double distance = CustomFunction::calDistance(point, point_origin);
            if(distance < minDistance && distance < dRadius){
                point_res = point;
                minDistance = distance;
            }
        }
    }

    return point_res;


}

bool CustomChart::setMeshTick(enTargetAxis axis, enMeshTickType type, double value){

    if(std::isnan(value)){
        _lastError = "value=nan";
        return false;
    }

    switch (type) {
    // 自动计算 -------------------------------------------
    case AUTO: {
        if(axis == AXIS_X){
            _meshTickTypeX = AUTO;
        }else if(axis == AXIS_Y){
            _meshTickTypeY = AUTO;
        }else{
            _meshTickTypeX = AUTO;
            _meshTickTypeY = AUTO;
        }
    }
        break;
    // 固定网格线数量 ------------------------------------------
    case FIXED_NUM: {
        if(value <= 0){
            _lastError = "numValue<0";
            return false;
        }
        if(axis == AXIS_X){
            _meshTickTypeX = FIXED_NUM;
            _meshNumX = value;
        }else if(axis == AXIS_Y){
            _meshTickTypeY = FIXED_NUM;
            _meshNumY = value;
        }else{
            _meshTickTypeX = FIXED_NUM;
            _meshTickTypeY = FIXED_NUM;
            _meshNumX = value;
            _meshNumY = value;
        }
    }
        break;
    // 固定网格间距
    case FIXED_SPACE: {
        if(value <= 0){
            _lastError = "spaceValue<0";
            return false;
        }
        if(axis == AXIS_X){
            _meshTickTypeX = FIXED_SPACE;
            _meshSpaceX = value;
        }else if(axis == AXIS_Y){
            _meshTickTypeY = FIXED_SPACE;
            _meshSpaceX = value;
        }else{
            _meshTickTypeX = FIXED_SPACE;
            _meshTickTypeY = FIXED_SPACE;
            _meshSpaceX = value;
            _meshSpaceX = value;
        }
    }
        break;
    default: {
        _lastError = "?????";
        return false;
    }
    }

    return true;
}

void CustomChart::calMesh(){

    // 计算网格间隔 (x轴)
    double xSpace = 1;
    switch (_meshTickTypeX) {
    case AUTO: {
        if(_fullMaxX-_fullMinX <= 10){
            xSpace = 1;
        }else{
            xSpace = std::ceil((_fullMaxX-_fullMinX) / 10);
        }
    }
        break;
    case FIXED_NUM: {
        xSpace = (_fullMaxX-_fullMinX) / _meshNumX;
    }
        break;
    case FIXED_SPACE: {
        xSpace = _meshSpaceX;
    }
        break;
    }
    // 计算网格间隔 (y轴)
    double ySpace = 1;
    switch (_meshTickTypeY) {
    case AUTO: {
        if(_fullMaxY-_fullMinY <= 10){
            ySpace = 1;
        }else{
            ySpace = std::ceil((_fullMaxY-_fullMinY) / 10);
        }
    }
        break;
    case FIXED_NUM: {
        ySpace = (_maxY-_minY) / _meshNumY;
    }
        break;
    case FIXED_SPACE: {
        ySpace = _meshSpaceY;
    }
        break;
    }

    // 以fullMinX和fullMinY为起点，计算tick的位置 ========================================================
    _tickPercentX.clear();
    _tickValueX.clear();
    _tickPercentY.clear();
    _tickValueY.clear();
    _fullTickPercentX.clear();
    _fullTickValueX.clear();
    _fullTickPercentY.clear();
    _fullTickValueY.clear();

    // x轴的tick计算 ------------------------
    // 开头
    _tickPercentX.push_back(0);
    _tickValueX.push_back(_minX);
    // 中间
    for(double curValue = xSpace; curValue < _maxX; curValue += xSpace){
        if(curValue > _minX){
            _tickValueX.push_back(curValue);
            _tickPercentX.push_back((curValue-_minX)/(_maxX-_minX));
        }
    }
    // 结尾
    _tickPercentX.push_back(1);
    _tickValueX.push_back(_maxX);

    // y轴的tick计算 -------------------------
    // 开头
    _tickPercentY.push_back(0);
    _tickValueY.push_back(_minY);
    // 中间
    for(double curValue = ySpace; curValue < _maxY; curValue += ySpace){
        if(curValue > _minY){
            _tickValueY.push_back(curValue);
            _tickPercentY.push_back((curValue-_minY)/(_maxY-_minY));
        }
    }
    // 结尾
    _tickPercentY.push_back(1);
    _tickValueY.push_back(_maxY);

    // fullTick版本
    // x轴的tick计算 ------------------------
    // 开头
    _fullTickPercentX.push_back(0);
    _fullTickValueX.push_back(_fullMinX);
    // 中间
    for(double curValue = xSpace; curValue < _fullMaxX; curValue += xSpace){
        if(curValue > _fullMinX){
            _fullTickValueX.push_back(curValue);
            _fullTickPercentX.push_back((curValue-_fullMinX)/(_fullMaxX-_fullMinX));
        }
    }
    // 结尾
    _fullTickPercentX.push_back(1);
    _fullTickValueX.push_back(_fullMaxX);

    // y轴的tick计算 -------------------------
    // 开头
    _fullTickPercentY.push_back(0);
    _fullTickValueY.push_back(_fullMinY);
    // 中间
    for(double curValue = ySpace; curValue < _fullMaxY; curValue += ySpace){
        if(curValue > _fullMinY){
            _fullTickValueY.push_back(curValue);
            _fullTickPercentY.push_back((curValue-_fullMinY)/(_fullMaxY-_fullMinY));
        }
    }
    // 结尾
    _fullTickPercentY.push_back(1);
    _fullTickValueY.push_back(_fullMaxY);


}


QString CustomChart::getLastError(){
    return _lastError;
}

